package com.dtp.core.monitor;

import cn.hutool.core.io.FileUtil;
import cn.hutool.system.RuntimeInfo;
import com.dtp.common.ApplicationContextHolder;
import com.dtp.core.support.ExecutorWrapper;
import com.dtp.common.entity.JvmStats;
import com.dtp.common.entity.Metrics;
import com.dtp.core.DtpRegistry;
import com.dtp.core.convert.MetricsConverter;
import com.dtp.core.support.MetricsAware;
import com.dtp.core.thread.DtpExecutor;
import com.google.common.collect.Lists;
import lombok.val;
import org.apache.commons.collections.MapUtils;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;

import java.util.List;

/**
 * 动态线程池端点类
 *
 * @Endpoint：定义一个监控端点，同时支持 HTTP 和 JMX 两种方式。
 * @WebEndpoint：定义一个监控端点，只支持 HTTP 方式。
 * @JmxEndpoint：定义一个监控端点，只支持 JMX 方式。
 * ----------------------------------------------------
 * @ReadOperation：作用在方法上，可用来返回端点展示的信息（通过 Get 方法请求）。
 * @WriteOperation：作用在方法上，可用来修改端点展示的信息（通过 Post 方法请求）。
 * @DeleteOperation：作用在方法上，可用来删除对应端点信息（通过 Delete 方法请求）。
 * @Selector：作用在参数上，用来定位一个端点的具体指标路由。
 *
 * @author yanhom
 * @since 1.0.0
 *
 * @remark muse
 **/
@Endpoint(id = "dynamic-tp")
public class DtpEndpoint {

    /** http://[ip]:[port]/actuator/dynamic-tp methods=[GET] */
    @ReadOperation
    public List<Metrics> invoke() {
        List<Metrics> metricsList = Lists.newArrayList();

        // 获得所有【Dtp线程池】的名称列表，通过线程池名称获得对应的线程池后，转换为ThreadPoolStats，保存到metricsList中
        List<String> dtpNames = DtpRegistry.listAllDtpNames();
        dtpNames.forEach(x -> {
            DtpExecutor executor = DtpRegistry.getDtpExecutor(x);
            metricsList.add(MetricsConverter.convert(executor));
        });

        // 获得所有【JUC线程池】的名称列表，通过线程池名称获得对应的线程池后，转换为ThreadPoolStats，保存到metricsList中
        List<String> commonNames = DtpRegistry.listAllCommonNames();
        commonNames.forEach(x -> {
            ExecutorWrapper wrapper = DtpRegistry.getCommonExecutor(x);
            metricsList.add(MetricsConverter.convert(wrapper));
        });

        // 从Spring中获得MetricsAware类型的类集合，并循环调用getMultiPoolStats方法获得ThreadPoolStats集合，保存到metricsList中
        val handlerMap = ApplicationContextHolder.getBeansOfType(MetricsAware.class);
        if (MapUtils.isNotEmpty(handlerMap))
            handlerMap.forEach((k, v) -> metricsList.addAll(v.getMultiPoolStats()));

        // 将jvm运行状态保存到metricsList中
        JvmStats jvmStats = new JvmStats();
        RuntimeInfo runtimeInfo = new RuntimeInfo();
        jvmStats.setMaxMemory(FileUtil.readableFileSize(runtimeInfo.getMaxMemory()));
        jvmStats.setTotalMemory(FileUtil.readableFileSize(runtimeInfo.getTotalMemory()));
        jvmStats.setFreeMemory(FileUtil.readableFileSize(runtimeInfo.getFreeMemory()));
        jvmStats.setUsableMemory(FileUtil.readableFileSize(runtimeInfo.getUsableMemory()));
        metricsList.add(jvmStats);

        return metricsList;
    }
}
